package cn.qianxun.meta.word.util;


import cn.qianxun.meta.word.replace.*;
import cn.qianxun.meta.word.vo.*;
import com.alibaba.fastjson.JSONObject;
import com.aspose.words.List;
import com.aspose.words.Shape;
import com.aspose.words.*;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;


/**
 * @Author fuzhilin
 * @Date 2020/12/31 0031 15:28
 * @Description 通过Aspose 实现word转pdf
 * 官网：https://www.componentsource.com/brand/aspose
 * 中文文档：https://www.evget.com/doclib/s/index
 */
public class AsposeUtil {

    /**
     * 校验license
     *
     * @return
     */
    public static boolean judgeLicense() {
        try {
            registerWord();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
//        boolean result = false;
//        try {
//            String licenseStr = "<License>\n" + "  <Data>\n" + "    <Products>\n" + "      <Product>Aspose.Total for Java</Product>\n" + "      <Product>Aspose.Words for Java</Product>\n" + "    </Products>\n" + "    <EditionType>Enterprise</EditionType>\n" + "    <SubscriptionExpiry>20991231</SubscriptionExpiry>\n" + "    <LicenseExpiry>20991231</LicenseExpiry>\n" + "    <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>\n" + "  </Data>\n" + "  <Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>\n" + "</License>";
//            InputStream is = new ByteArrayInputStream(licenseStr.getBytes("UTF-8"));
//            License aposeLic = new License();
//            aposeLic.setLicense(is);
//            result = true;
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        return true;
    }

    /**
     * 转换
     *
     * @param filePath  word文档路径
     * @param pdfPath   需要转换的pdf路径
     * @param type      类型 doc docx
     * @param ambient   环境true:win false:linux
     * @param watermark 需要添加的水印
     */
    public static int trans(String filePath, String pdfPath, String type, Boolean ambient, String watermark) {
        if (!judgeLicense()) {
        }
        try {
            System.out.println("as开始：" + filePath);
            long old = System.currentTimeMillis();
            File file = new File(pdfPath);
            if ("doc".equals(type) || "docx".equals(type)) {
                wordOfPdf(file, filePath, ambient, watermark);
            } else {
                return 0;
            }
            long now = System.currentTimeMillis();
            System.out.println("完成：" + pdfPath);
            System.out.println("共耗时：" + ((now - old) / 1000.0) + "秒");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 1;
    }

    /**
     * @param file      pdf文件路径
     * @param filePath  word文档路径
     * @param ambient   环境true:win false:linux
     * @param watermark 需要添加的水印
     */
    private static void wordOfPdf(File file, String filePath, Boolean ambient, String watermark) {
        //获取所有用户的字体
        String userfontsfoloder;
        if (ambient) {
            userfontsfoloder = "C:\\Users\\Administrator\\AppData\\Local" + "\\Microsoft\\Windows\\Fonts\\";
        } else {
            userfontsfoloder = "/usr/share/fonts/Fonts";
        }
        FontSourceBase[] updatedFontSources = FontSettings.getDefaultInstance().getFontsSources();
        FontSourceBase[] updatedFontSourcesNew = new FontSourceBase[updatedFontSources.length + 1];
        System.arraycopy(updatedFontSources, 0, updatedFontSourcesNew, 0, updatedFontSources.length);
        //将用户目录字体添加到字体源中
        FolderFontSource folderFontSource = new FolderFontSource(userfontsfoloder, true);
        updatedFontSourcesNew[updatedFontSources.length] = folderFontSource;
        FontSettings.getDefaultInstance().setFontsSources(updatedFontSourcesNew);
        //开始转换
        FileOutputStream os = null;
        Document doc;
        try {
            os = new FileOutputStream(file);
            doc = new Document(filePath);
            //添加图片水印
            //insertWatermarkImg(doc,"logo.png");
            //添加文字水印
            if (StringUtils.isNotEmpty(watermark)) {
                insertWatermarkText(doc, watermark);
            }
            doc.save(os, SaveFormat.PDF);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @param wordInputStream word文件输入流
     * @param pdfPath         pdf文档路径
     * @param ambient         环境true:win false:linux
     * @param watermark       需要添加的水印
     */
    public static void wordOfPdfTool(InputStream wordInputStream, String pdfPath, Boolean ambient, String watermark) {
        System.out.println("word转PDF开始");
        long old = System.currentTimeMillis();
        if (!judgeLicense()) {
            throw new RuntimeException("License invalid");
        }
        //获取所有用户的字体
        String userfontsfoloder;
        if (ambient) {
            userfontsfoloder = "C:\\Users\\Administrator\\AppData\\Local" + "\\Microsoft\\Windows\\Fonts\\";
        } else {
            userfontsfoloder = "/usr/share/fonts/Fonts";
        }
        FontSourceBase[] updatedFontSources = FontSettings.getDefaultInstance().getFontsSources();
        FontSourceBase[] updatedFontSourcesNew = new FontSourceBase[updatedFontSources.length + 1];
        System.arraycopy(updatedFontSources, 0, updatedFontSourcesNew, 0, updatedFontSources.length);
        //将用户目录字体添加到字体源中
        FolderFontSource folderFontSource = new FolderFontSource(userfontsfoloder, true);
        updatedFontSourcesNew[updatedFontSources.length] = folderFontSource;
        FontSettings.getDefaultInstance().setFontsSources(updatedFontSourcesNew);
        //开始转换
        FileOutputStream os = null;
        Document doc;
        try {
            os = new FileOutputStream(pdfPath);
            doc = new Document(wordInputStream);
            //添加图片水印
            //insertWatermarkImg(doc,"logo.png");
            //添加文字水印
            if (StringUtils.isNotEmpty(watermark)) {
                insertWatermarkText(doc, watermark);
            }
            doc.save(os, SaveFormat.PDF);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        long now = System.currentTimeMillis();
        System.out.println("word转PDF完成共耗时：" + ((now - old) / 1000.0) + "秒");
    }

    /**
     * 删除文件
     *
     * @param filePathAndName 指定的路径
     */
    public static void delFile(String filePathAndName) {
        try {
            File file = new File(filePathAndName);
            boolean delete = file.delete();
            if (delete) {
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * @param doc           需要添加的文档
     * @param watermarkText 水印内容
     * @throws Exception
     * @Title: insertWatermarkText
     * @Description: PDF生成水印 （基本水印 详情参照 WatermarkUtil）
     * @author fuzhilin
     */
    private static void insertWatermarkText(Document doc, String watermarkText) throws Exception {
        Shape watermark = new Shape(doc, ShapeType.TEXT_PLAIN_TEXT);
        //水印内容
        watermark.getTextPath().setText(watermarkText);
        //水印字体
        watermark.getTextPath().setFontFamily("宋体");
        //水印宽度
        watermark.setWidth(500);
        //水印高度
        watermark.setHeight(100);
        //旋转水印
        watermark.setRotation(-40);
        //水印颜色
        watermark.getFill().setColor(Color.lightGray);
        watermark.setStrokeColor(Color.lightGray);
        watermark.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
        watermark.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
        watermark.setWrapType(WrapType.NONE);
        watermark.setVerticalAlignment(VerticalAlignment.CENTER);
        watermark.setHorizontalAlignment(HorizontalAlignment.CENTER);
        Paragraph watermarkPara = new Paragraph(doc);
        watermarkPara.appendChild(watermark);
        for (Section sect : doc.getSections()) {
            insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_PRIMARY);
            insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_FIRST);
            insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_EVEN);
        }
    }


    /**
     * word文档插入图片水印
     *
     * @param doc     文档对象
     * @param imgPath 图片路径
     * @throws Exception
     */
    public static void insertWatermarkImg(Document doc, String imgPath) throws Exception {
        if (StringUtils.isEmpty(imgPath)) {
            System.out.println("没有配置水印图片, 无法为文档加入水印");
            return;
        }
        Paragraph watermarkPara = new Paragraph(doc);
        Shape waterShape = buildImgShape(doc, imgPath);
        watermarkPara.appendChild(waterShape);
        // 在每个部分中，最多可以有三个不同的标题，因为我们想要出现在所有页面上的水印，插入到所有标题中。
        for (Section sect : doc.getSections()) {
            // 每个区段可能有多达三个不同的标题，因为我们希望所有页面上都有水印，将所有的头插入。
            insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_PRIMARY);
            insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_FIRST);
            insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_EVEN);
        }
    }

    /**
     * 构建图片shape类
     *
     * @param doc     文档对象
     * @param imgPath 图片文件路径
     */
    private static Shape buildImgShape(Document doc, String imgPath) {
        Shape shape = new Shape(doc, ShapeType.IMAGE);
        try {
            BufferedImage sourceImg = ImageIO.read(WatermarkUtil.class.getClassLoader().getResourceAsStream(imgPath));
            shape.getImageData().setImage(sourceImg);
            shape.setWidth(200);
            shape.setHeight(50);
            shape.setLeft(100);
            shape.setTop(100);
            shape.setWrapType(WrapType.NONE);
        } catch (Exception e) {
            throw new RuntimeException("图片附件丢失, 无法生成水印!", e);
        }
        return shape;
    }


    /**
     * 插入水印
     *
     * @param watermarkPara 水印段落
     * @param sect          部件
     * @param headerType    头标类型字段
     * @throws Exception
     */
    private static void insertWatermarkIntoHeader(Paragraph watermarkPara, Section sect, int headerType) throws Exception {
        HeaderFooter header = sect.getHeadersFooters().getByHeaderFooterType(headerType);
        if (header == null) {
            header = new HeaderFooter(sect.getDocument(), headerType);
            sect.getHeadersFooters().add(header);
        }
        header.appendChild(watermarkPara.deepClone(true));
    }


    /**
     * 保存pdf
     *
     * @param path    保存目录
     * @param doc     原文档
     * @param ambient 环境true:win false:linux
     */
    public static void savePdf(String path, Document doc, Boolean ambient) {
        String format = "pdf";
        save(path, doc, SaveFormat.PDF, format, ambient);
    }

    /**
     * 保存doc
     *
     * @param path    保存目录
     * @param doc     原文档
     * @param ambient 环境true:win false:linux
     */
    public static void saveDoc(String path, Document doc, Boolean ambient) {
        String format = "doc";
        save(path, doc, SaveFormat.DOC, format, ambient);
    }

    public static void saveDocx(String path, Document doc, Boolean ambient) {
        String format = "docx";
        save(path, doc, SaveFormat.DOCX, format, ambient);
    }

    /**
     * 保存各种格式的文档
     *
     * @param path       保存地址
     * @param doc        保存文件
     * @param saveFormat 保存格式
     * @param ambient    环境true:win false:linux
     */
    private static void save(String path, Document doc, int saveFormat, String format, Boolean ambient) {
        if (!judgeLicense()) {
        }
        try {
            //获取所有用户的字体
            String userfontsfoloder;
            if (ambient) {
                userfontsfoloder = "C:\\Users\\Administrator\\AppData\\Local" + "\\Microsoft\\Windows\\Fonts\\";
            } else {
                userfontsfoloder = "/usr/share/fonts/Fonts";
            }
            FontSourceBase[] updatedFontSources = FontSettings.getDefaultInstance().getFontsSources();
            FontSourceBase[] updatedFontSourcesNew = new FontSourceBase[updatedFontSources.length + 1];
            System.arraycopy(updatedFontSources, 0, updatedFontSourcesNew, 0, updatedFontSources.length);
            //将用户目录字体添加到字体源中
            FolderFontSource folderFontSource = new FolderFontSource(userfontsfoloder, true);
            updatedFontSourcesNew[updatedFontSources.length] = folderFontSource;
            FontSettings.getDefaultInstance().setFontsSources(updatedFontSourcesNew);
            doc.save(path, saveFormat);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 制作报表正文
     *
     * @param builder
     * @param text
     */
    public static void setText(DocumentBuilder builder, String text) {
        try {
            builder.getParagraphFormat().clearFormatting();
            /*List list = builder.getDocument().getLists().add(ListTemplate.NUMBER_DEFAULT);
            list.getListLevels().get(0).setAlignment(ListLevelAlignment.LEFT);
            //将我们的列表应用于某些段落。
            builder.getListFormat().setList(list);*/
            builder.getParagraphFormat().setLeftIndent(25.0);
            // 3-将间距设置为默认行距的倍数，默认为12点。
            //这种间距将缩放为不同的字体大小。
            //builder.getParagraphFormat().setLineSpacingRule(LineSpacingRule.MULTIPLE);
            builder.getParagraphFormat().setLineSpacing(18.0);
            builder.getFont().setNameFarEast("仿宋_GB2312");//字体
            builder.getFont().setSize(16);
            builder.getFont().setBold(false);//粗体
            builder.getFont().setItalic(false);//斜体
            builder.writeln(text);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 制作报表总标题
     *
     * @param builder
     * @param title
     */
    public static void setTitle(DocumentBuilder builder, String title) {
        try {
            //设置字体格式
            builder.insertHtml("<p style='text-align:center'><font face='宋体' size='30' color='black'>" + title + "</font></p>");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 制作目录
     *
     * @param builder
     */
    public static void setCatalogue(DocumentBuilder builder) {
        try {
            builder.insertTableOfContents("\\o \"1-3\" \\h \\z \\u");
            builder.insertBreak(BreakType.PAGE_BREAK);
            builder.writeln();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 制作一级标题
     *
     * @param builder
     */
    public static void setTitle1(DocumentBuilder builder, String title1) {
        try {
            builder.getParagraphFormat().clearFormatting();
            builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_1);
            List list = builder.getDocument().getLists().add(ListTemplate.NUMBER_UPPERCASE_LETTER_DOT);
            list.getListLevels().get(0).setAlignment(ListLevelAlignment.LEFT);
            //将我们的列表应用于某些段落。
            builder.getListFormat().setList(list);
            builder.getFont().setNameFarEast("黑体");
            builder.getFont().setSize(16);
            builder.getFont().setBold(false);//粗体
            builder.write(title1);
            builder.writeln();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
/*
    public static void main(String[] args) {
        try {
            AsposeUtil.saveDoc("E:\\123.doc", new Document(), true);
            String template = "E:\\123.doc";
            Document doc = new Document(template);
            DocumentBuilder builder = new DocumentBuilder();
            builder.setDocument(doc);
            //AsposeUtil.setCatalogue(builder);
            AsposeUtil.setTitle1(builder, "检查结果");
            AsposeUtil.setTitle2(builder, "管理与服务类安全检查");
            AsposeUtil.setText(builder, "通过查阅相关文件、记录等方式，检查了安全主管机构及责任分工、安全责任制落实、安全自查自管工作落实等情况。相关检查依据主要出自《中华人民共和国网络安全法》《网络安全等级保护基本要求》《数据安全管理办法》。");
            AsposeUtil.setTitle3(builder, "安全责任制落实情况");
            AsposeUtil.setText(builder,"已基本落实网络安全责任制，与各二级单位签订网络安全责任书，划分网络安全责任边界；。");
            AsposeUtil.saveDoc("E:\\456.doc", doc, true);
            delFile("E:\\123.doc");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }*/

    /**
     * 制作二级标题
     *
     * @param builder
     */
    public static void setTitle2(DocumentBuilder builder, String title2) {
        try {
            builder.getParagraphFormat().clearFormatting();
            builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_2);
           /* List list = builder.getDocument().getLists().add(ListTemplate.NUMBER_LOWERCASE_LETTER_PARENTHESIS);
            list.getListLevels().get(0).setAlignment(ListLevelAlignment.LEFT);
            //将我们的列表应用于某些段落。
            builder.getListFormat().setList(list);*/
            builder.getFont().setNameFarEast("楷体");//字体
            builder.getFont().setSize(16);
            builder.getFont().setBold(false);//粗体
            builder.getFont().setItalic(false);//斜体
            builder.write(title2);
            builder.writeln();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 制作三级标题
     *
     * @param builder
     */
    public static void setTitle3(DocumentBuilder builder, String title3) {
        try {
            builder.getParagraphFormat().clearFormatting();
            builder.getParagraphFormat().setStyleIdentifier(StyleIdentifier.HEADING_3);
            //builder.insertBreak(BreakType.PAGE_BREAK);
            List list = builder.getDocument().getLists().add(ListTemplate.NUMBER_DEFAULT);
            list.getListLevels().get(0).setAlignment(ListLevelAlignment.LEFT);
            //将我们的列表应用于某些段落。
            builder.getListFormat().setList(list);
            builder.getFont().setNameFarEast("仿宋_GB2312");
            builder.getFont().setSize(16);
            builder.getFont().setBold(true);//粗体
            builder.getFont().setItalic(false);//斜体
            builder.write(title3);
            builder.writeln();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 制作报表段落
     *
     * @param builder
     * @param pragraph
     */
    public static void setParagraph(DocumentBuilder builder, String pragraph) {
        try {
            //设置字体格式
            builder.insertHtml("<p><font face='宋体'>&nbsp;&nbsp; " + pragraph + "</font></p>");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 制作一个单元格并追加数据,单元格不合并
     *
     * @param builder
     * @param width   设置单元格宽度
     * @param text
     */
    public static void setCell(DocumentBuilder builder, Double width, String text) {
        builder.insertCell();
        if (width == null) {
            width = 3d;
        }
        builder.getCellFormat().setWidth(width);
        builder.getCellFormat().setVerticalMerge(CellMerge.NONE);
        builder.write(text);
    }

    /**
     * 插入单元格，不设置宽度,单元格不合并
     *
     * @param builder
     * @param text
     */
    public static void setCell(DocumentBuilder builder, String text) {
        builder.insertCell();
        builder.getCellFormat().setVerticalMerge(CellMerge.NONE);
        builder.getCellFormat().setVerticalAlignment(CellVerticalAlignment.CENTER);
        builder.write(text);
    }

    public static void setCell(DocumentBuilder builder, Long text) {
        builder.insertCell();
        builder.getCellFormat().setVerticalMerge(CellMerge.NONE);
        builder.getCellFormat().setVerticalAlignment(CellVerticalAlignment.CENTER);
        if (text == null) {
            builder.write("");
        } else {
            builder.write(text.toString());
        }
    }

    public static void setCell(DocumentBuilder builder, Double text) {
        builder.insertCell();
        builder.getCellFormat().setVerticalMerge(CellMerge.NONE);
        builder.getCellFormat().setVerticalAlignment(CellVerticalAlignment.CENTER);
        if (text == null) {
            builder.write("");
        } else {
            builder.write(text.toString());
        }
    }

    /**
     * 垂直合并单元格的第一格
     *
     * @param builder
     * @param text
     */
    public static void setStartVerticalMerge(DocumentBuilder builder, String text) {
        builder.insertCell();
        builder.getCellFormat().setVerticalMerge(CellMerge.FIRST);
        builder.getCellFormat().setVerticalAlignment(CellVerticalAlignment.CENTER);
        builder.write(text);
    }

    /**
     * 垂直合并单元格的后面格
     *
     * @param builder
     */
    public static void setThenVerticalMerge(DocumentBuilder builder) {
        builder.insertCell();
        // This cell is vertically merged to the cell above and should be empty.
        builder.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS);
        builder.getCellFormat().setVerticalAlignment(CellVerticalAlignment.CENTER);
    }

    /**
     * 水平合并单元格的第一格
     *
     * @param builder
     * @param text
     */
    public static void setStartHorizontalMerge(DocumentBuilder builder, String text) {
        builder.insertCell();
        builder.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
        builder.write(text);
    }

    /**
     * 水平合并单元格的后面格
     *
     * @param builder
     */
    public static void setThenHorizontalMerge(DocumentBuilder builder) {
        builder.insertCell();
        // This cell is vertically merged to the cell above and should be empty.
        builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
    }

    /**
     * 制作表格数据行
     *
     * @param builder
     */
    public static void setRow(DocumentBuilder builder) {
        try {
            builder.getRowFormat().setHeadingFormat(true);
            builder.getRowFormat().getBorders().setLineStyle(LineStyle.SINGLE);
            builder.getRowFormat().setHeightRule(HeightRule.AUTO);
            builder.getRowFormat().setAllowBreakAcrossPages(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 制作表格
     *
     * @param builder
     * @throws Exception
     */
    public static Table setTable(DocumentBuilder builder) {
        builder.moveToDocumentEnd();
        Table table = builder.startTable();
        builder.getParagraphFormat().setAlignment(ParagraphAlignment.CENTER);
        return table;
    }

    /**
     * aspose word 替换文字/图片。
     *
     * @param stream    原文件路径
     * @param saveUrl   保存路径
     * @param paramMap  {key:value,"$年份$":"2020","$签字1$":"$pic:d/qz1.jpg"} key 为要被替换的字符串，value 为替换为的字符串，替换为图片，则value为$pic:+图片路径
     * @param watermark 是否水印
     * @param flag      是否生成pdf
     * @return
     */
    public static boolean replace(InputStream stream, String saveUrl, Map<String, String> paramMap, String watermark, Boolean flag) {
        if (!judgeLicense()) {
            System.out.println("license错误");
        }
        if (stream == null) {
            return false;
        }
        if (saveUrl == null || saveUrl.isEmpty()) {
            return false;
        }
        if (paramMap == null || paramMap.isEmpty()) {
            return false;
        }
        try {
            Document doc = new Document(stream);
            Iterator<String> paramKey = paramMap.keySet().iterator();
            while (paramKey.hasNext()) {
                String key = paramKey.next();
                String v = StringUtils.defaultIfEmpty(paramMap.get(key), "");
                if (v.startsWith("$pic:")) {
                    v = v.substring(5);
                    //如果key已经被替换成图片了，那就要将图片替换成新的图片，相当于重新插入图片
                    NodeCollection shapeCollection = doc.getChildNodes(NodeType.SHAPE, true);
                    Iterator<Shape> shapeIterate = shapeCollection.iterator();
                    java.util.List<Shape> shaplist = new ArrayList<Shape>();
                    while (shapeIterate.hasNext()) {
                        Shape shape = shapeIterate.next();
                        if (key.equals(shape.getName())) {
                            shaplist.add(shape);
                        }
                    }
                    DocumentBuilder builder = new DocumentBuilder(doc);
                    for (int i = 0; i < shaplist.size(); i++) {
                        Shape shape = shaplist.get(i);
                        //将光标移动到指定节点
                        builder.moveTo(shape);
                        Shape img = builder.insertImage(v);
                        img.setName(key);
                        System.out.println("replace" + key);
                        shape.remove();
                    }
                    //替换文字为图片
                    doc.getRange().replace(key, "", new FindReplaceOptions(new ReplaceAndInsertImage(v, key)));
                } else if (v.startsWith("$chart:")) {
                    v = v.substring(7);
                    GenerateChartVO chartVO = JSONObject.parseObject(v, GenerateChartVO.class);
                    doc.getRange().replace(key, "", new FindReplaceOptions(new ReplaceAndInsertChart(key, chartVO)));
                } else if (v.startsWith("$table:")) {
                    if ("1".equals(v.substring(7, 8))) {
                        v = v.substring(8);
                        GenerateManyMultTableVO tableVO = JSONObject.parseObject(v, GenerateManyMultTableVO.class);
                        doc.getRange().replace(key, "", new FindReplaceOptions(new ReplaceAndInsertMunltTable(key, tableVO)));
                    } else {
                        v = v.substring(7);
                        GenerateTableVO tableVO = JSONObject.parseObject(v, GenerateTableVO.class);
                        doc.getRange().replace(key, "", new FindReplaceOptions(new ReplaceAndInsertTable(key, tableVO)));
                    }
                } else if (v.startsWith("$tableNew:")) {
                    v = v.substring(10);
                    GenerateTableVO tableVO = JSONObject.parseObject(v, GenerateTableVO.class);
                    doc.getRange().replace(key, "", new FindReplaceOptions(new ReplaceAndInsertNewTable(key, tableVO)));
                } else if (v.startsWith("$barPerStaChart:")) {
                    v = v.substring(16);
                    GenerateChartVO generateChartVO = JSONObject.parseObject(v, GenerateChartVO.class);
                    doc.getRange().replace(key, "", new FindReplaceOptions(new BarPercentStackedChart(key, generateChartVO)));

                } else {
                    doc.getRange().replace(key, v);
                }
            }
            if (null != watermark && "" != watermark && "1".equals(watermark)) {
                //添加图片水印
                WatermarkUtil.insertWatermarkImg(doc, "logo.png");
            }
            // 更新域
            doc.updateFields();
            doc.save(saveUrl);
            String osName = System.getProperty("os.name").toLowerCase();
            if (flag) {
                saveUrl = saveUrl.replace(".docx", ".pdf");
                if (osName.contains("window")) {
                    savePdf(saveUrl, doc, true);
                } else if (osName.contains("nux")) {
                    savePdf(saveUrl, doc, false);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * aspose word 替换文字/图片。
     *
     * @param stream    原文件路径
     * @param saveUrl   保存路径
     * @param paramMap  {key:value,"$年份$":"2020","$签字1$":"$pic:d/qz1.jpg"} key 为要被替换的字符串，value 为替换为的字符串，替换为图片，则value为$pic:+图片路径
     * @param watermark 是否水印
     * @param flag      是否生成pdf
     * @return
     */
    public static Document replace4Doc(InputStream stream, String saveUrl, Map<String, String> paramMap, String watermark, Boolean flag) {
        if (!judgeLicense()) {
            System.out.println("license错误");
        }
        if (stream == null) {
            return null;
        }
        if (saveUrl == null || saveUrl.isEmpty()) {
            return null;
        }
        if (paramMap == null || paramMap.isEmpty()) {
            return null;
        }
        try {
            Document doc = new Document(stream);
            Iterator<String> paramKey = paramMap.keySet().iterator();
            while (paramKey.hasNext()) {
                String key = paramKey.next();
                String v = StringUtils.defaultIfEmpty(paramMap.get(key), "");
                if (v.startsWith("$pic:")) {
                    v = v.substring(5);
                    //如果key已经被替换成图片了，那就要将图片替换成新的图片，相当于重新插入图片
                    NodeCollection shapeCollection = doc.getChildNodes(NodeType.SHAPE, true);
                    Iterator<Shape> shapeIterate = shapeCollection.iterator();
                    java.util.List<Shape> shaplist = new ArrayList<Shape>();
                    while (shapeIterate.hasNext()) {
                        Shape shape = shapeIterate.next();
                        if (key.equals(shape.getName())) {
                            shaplist.add(shape);
                        }
                    }
                    DocumentBuilder builder = new DocumentBuilder(doc);
                    for (int i = 0; i < shaplist.size(); i++) {
                        Shape shape = shaplist.get(i);
                        //将光标移动到指定节点
                        builder.moveTo(shape);
                        Shape img = builder.insertImage(v);
                        img.setName(key);
                        System.out.println("replace" + key);
                        shape.remove();
                    }
                    //替换文字为图片
                    doc.getRange().replace(key, "", new FindReplaceOptions(new ReplaceAndInsertImage(v, key)));
                } else if (v.startsWith("$chart:")) {
                    v = v.substring(7);
                    GenerateChartVO chartVO = JSONObject.parseObject(v, GenerateChartVO.class);
                    doc.getRange().replace(key, "", new FindReplaceOptions(new ReplaceAndInsertChart(key, chartVO)));
                } else if (v.startsWith("$table:")) {
                    if ("1".equals(v.substring(7, 8))) {
                        v = v.substring(8);
                        GenerateManyMultTableVO tableVO = JSONObject.parseObject(v, GenerateManyMultTableVO.class);
                        doc.getRange().replace(key, "", new FindReplaceOptions(new ReplaceAndInsertMunltTable(key, tableVO)));
                    } else {
                        v = v.substring(7);
                        GenerateTableVO tableVO = JSONObject.parseObject(v, GenerateTableVO.class);
                        doc.getRange().replace(key, "", new FindReplaceOptions(new ReplaceAndInsertTable(key, tableVO)));
                    }
                } else if (v.startsWith("$barPerStaChart:")) {
                    v = v.substring(16);
                    GenerateChartVO generateChartVO = JSONObject.parseObject(v, GenerateChartVO.class);
                    doc.getRange().replace(key, "", new FindReplaceOptions(new BarPercentStackedChart(key, generateChartVO)));

                } else {
                    doc.getRange().replace(key, v);
                }
            }
            if (null != watermark && "" != watermark && "1".equals(watermark)) {
                //添加图片水印
                WatermarkUtil.insertWatermarkImg(doc, "logo.png");
            }
            // 更新域
            doc.updateFields();
            doc.save(saveUrl);
            String osName = System.getProperty("os.name").toLowerCase();
            if (flag) {
                saveUrl = saveUrl.replace(".docx", ".pdf");
                if (osName.contains("window")) {
                    savePdf(saveUrl, doc, true);
                } else if (osName.contains("nux")) {
                    savePdf(saveUrl, doc, false);
                }
            }
            return doc;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void testWord() {
        try {
            Document doc = new Document("G:\\123.doc");
            NodeCollection childNodes = doc.getChildNodes();

            for (int i = 0; i < childNodes.getCount(); i++) {
                Node node = childNodes.get(i);
                System.out.println(node.getText());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }


    /**
     * 获取所有的标题，并返回父ID和自身ID来构建树结构
     *
     * @param doc
     * @return
     */
    public static ArrayList<HeadingVo> getAllHeading(Document doc) {
        ArrayList<HeadingVo> headingList = new ArrayList<HeadingVo>();
        // 获取所有段落
        NodeCollection paragraphs = doc.getChildNodes(NodeType.PARAGRAPH, true);
        // 遍历所有段落，查找标题
        String parentId = "0";
        for (Paragraph paragraph : (Iterable<Paragraph>) paragraphs) {
            // 判断段落是否为标题
            if (1 <= paragraph.getParagraphFormat().getStyleIdentifier() && paragraph.getParagraphFormat().getStyleIdentifier() <= 9) {
                int styleIdentifier = paragraph.getParagraphFormat().getStyleIdentifier();
                HeadingVo headingVo = new HeadingVo();
                // 输出标题文本内容
                // System.out.println(paragraph.getText().trim());
                headingVo.setName(paragraph.getText().trim());
                headingVo.setNum(styleIdentifier);
                if (styleIdentifier == 1) {
                    headingVo.setPid("0");
                } else {
                    headingVo.setPid(getPid(headingList, styleIdentifier));
                }
                headingVo.setId(UUID.randomUUID().toString().replace("-", ""));
                headingList.add(headingVo);
            }
        }
        return headingList;
    }

    /**
     * 获取对应标题的父标题的ID
     *
     * @param headingList
     * @param styleIdentifier 当前级别
     * @return
     */
    public static String getPid(ArrayList<HeadingVo> headingList, int styleIdentifier) {
        for (int i = headingList.size() - 1; i >= 0; i--) {
            HeadingVo element = headingList.get(i);
            if (element.getNum() + 1 == styleIdentifier) {
                return element.getId();
            }
        }
        return "0";
    }

    public static Boolean changeDocFormat(Document doc) {


        // 设置标题的字体、大小和自动编号序列
        NodeCollection paragraphs = doc.getChildNodes(NodeType.PARAGRAPH, true);
        int heading1Counter = 1;
        int heading2Counter = 1;
        for (Paragraph paragraph : (Iterable<Paragraph>) paragraphs) {
            if (paragraph.getParagraphFormat().getStyleIdentifier() == StyleIdentifier.HEADING_1) {
                paragraph.getListFormat().setList(doc.getLists().add(ListTemplate.OUTLINE_HEADINGS_NUMBERS));
                paragraph.getListFormat().setListLevelNumber(0);
            } else if (paragraph.getParagraphFormat().getStyleIdentifier() == StyleIdentifier.HEADING_2) {
                paragraph.getListFormat().setList(doc.getLists().add(ListTemplate.OUTLINE_HEADINGS_NUMBERS));
                paragraph.getListFormat().setListLevelNumber(1);
            }
            paragraph.getParagraphFormat().getStyle().getFont().setSize(16); // 设置字体大小
            paragraph.getParagraphFormat().getStyle().getFont().setName("Arial"); // 设置字体
            paragraph.getParagraphFormat().setAlignment(ParagraphAlignment.LEFT); // 设置标题居中显示
        }

        // 修改正文的大小
        NodeCollection runs = doc.getChildNodes(NodeType.RUN, true);
        for (Run run : (Iterable<Run>) runs) {
            run.getFont().setSize(12); // 设置字体大小
            run.getFont().setName("Times New Roman"); // 设置字体
        }
        // 保存文档
        try {
            doc.save("G:\\123456.doc");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return true;
    }


    public static void MergeSpecifiedCells(Document doc, java.util.List<MergeTableParamVO> paramVOList) throws Exception {
        Table table = doc.getFirstSection().getBody().getTables().get(0);
        if (cn.qianxun.meta.common.core.utils.StringUtils.isNull(table)) {
            return;
        }
        for (MergeTableParamVO paramVO : paramVOList) {
            Cell cellStartRange = table.getRows().get(paramVO.getStartLine()).getCells().get(paramVO.getStartColumn());
            Cell cellEndRange = table.getRows().get(paramVO.getEndLine()).getCells().get(paramVO.getEndColumn());
            //合并
            MergeCells(cellStartRange, cellEndRange);
            //单元格添加斜线
            if (cn.qianxun.meta.common.core.utils.StringUtils.isNotNull(paramVO.getBorderType())) {
                Border byBorderType1 = cellStartRange.getCellFormat().getBorders().getByBorderType(paramVO.getBorderType());
                byBorderType1.setColor(Color.black);
                byBorderType1.setLineWidth(0.5);
            }
        }
    }

    public static void MergeCells(Cell startCell, Cell endCell) {
        Table parentTable = startCell.getParentRow().getParentTable();
        // Find the row and cell indices for the start and end cell.
        Point startCellPos = new Point(startCell.getParentRow().indexOf(startCell), parentTable.indexOf(startCell.getParentRow()));
        Point endCellPos = new Point(endCell.getParentRow().indexOf(endCell), parentTable.indexOf(endCell.getParentRow()));
        // Create the range of cells to be merged based off these indices. Inverse each index if the end cell if before the start cell.
        Rectangle mergeRange = new Rectangle(Math.min(startCellPos.x, endCellPos.x), Math.min(startCellPos.y, endCellPos.y), Math.abs(endCellPos.x - startCellPos.x) + 1, Math.abs(endCellPos.y - startCellPos.y) + 1);
        for (Row row : parentTable.getRows()) {
            for (Cell cell : row.getCells()) {
                Point currentPos = new Point(row.indexOf(cell), parentTable.indexOf(row));

                // Check if the current cell is inside our merge range then merge it.
                if (mergeRange.contains(currentPos)) {
                    if (currentPos.x == mergeRange.x) {
                        cell.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
                    } else {
                        cell.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
                    }
                    if (currentPos.y == mergeRange.y) {
                        cell.getCellFormat().setVerticalMerge(CellMerge.FIRST);
                    } else {
                        cell.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS);
                    }
                }
            }
        }

    }

    public static Document generateDirectory(Document doc, String name) {
        if (!judgeLicense()) {
            System.out.println("license错误");
        }
        // Fill the empty table of contents
        try {
            // Create the DocumentBuilder object
            DocumentBuilder builder = new DocumentBuilder(doc);

            // Instantiate ParagraphFormat object
            ParagraphFormat paragraphFormat = builder.getParagraphFormat();

            // Get the existing style name
            String defaultStyle = paragraphFormat.getStyleName();

            // Set style and alignment of the table of contents
            paragraphFormat.setStyleName("Title");
            paragraphFormat.setAlignment(ParagraphAlignment.CENTER);

            // Add title for table of contents
            builder.getFont().setSize(24);  // 设置字体大小为24磅
            builder.getFont().setBold(true);  // 设置字体加粗
            builder.writeln(name);
            builder.getParagraphFormat().setAlignment(ParagraphAlignment.CENTER);  // 居中对齐
            builder.writeln("目录");

            // Set back the text style
            paragraphFormat.setStyleName(defaultStyle);

            // Insert a table of contents with switches
            builder.insertTableOfContents("\\o \"1-3\" \\h \\z \\u");
            builder.insertBreak(BreakType.PAGE_BREAK);
            doc.updateFields();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return doc;

    }

    /**
     * aspose-words:jdk17:23.4 版本
     */
    public static void registerWord() throws Exception {
        // 构造一个注册信息
        Class<?> zzXgCClass = Class.forName("com.aspose.words.zzXgC");
        Constructor<?> constructors = zzXgCClass.getDeclaredConstructors()[0];
        constructors.setAccessible(true);
        Object instance = constructors.newInstance("zzW5k", "zzYON");
        // zzXFN = 1
        Field zzXFN = zzXgCClass.getDeclaredField("zzXFN");
        zzXFN.setAccessible(true);
        zzXFN.set(instance, 1);
        // zzW8s = 0
        // zzX6D = "8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7" // SerialNumber
        // zzw9 SubscriptionExpiry
        // zzZq3 LicenseExpiry
        // zzW5k <Data> ...
        // zzYON 签名 Signature
        // zzXjC zzZoT 对象 空


        // 把注册信息放到 zzYVA这个类中来
        Class<?> zzYVAClass = Class.forName("com.aspose.words.zzYVA");
        Field zzwP = zzYVAClass.getDeclaredField("zzwP");
        zzwP.setAccessible(true);
        ArrayList<Object> zzwPValue = new ArrayList<>();
        zzwPValue.add(instance);
        zzwP.set(null, zzwPValue);

        // 生成文档会掉这个来判断 zzXQo
        Class<?> zzXQoClass = Class.forName("com.aspose.words.zzXQo");
        Field zzHA = zzXQoClass.getDeclaredField("zzHA");
        zzHA.setAccessible(true);
        zzHA.set(null, 128);
        Field zzWod = zzXQoClass.getDeclaredField("zzWod");
        zzWod.setAccessible(true);
        zzWod.set(null, false);
    }

}
